package com.ruoyi.finance.livestreaming.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.util.StringUtil;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.finance.livestreaming.entity.*;
import com.ruoyi.finance.livestreaming.mapper.*;
import com.ruoyi.finance.livestreaming.service.FiDigitalLivestreamingUserService;
import com.ruoyi.finance.rules.entity.SzOtherRule;
import com.ruoyi.finance.rules.entity.SzUser;
import com.ruoyi.finance.rules.mapper.SzUserMapper;
import com.ruoyi.finance.rules.task.SZRuleCache;
import com.ruoyi.module.utils.BigDecimalChain;
import com.ruoyi.module.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FiDigitalLivestreamingUserServiceImpl implements FiDigitalLivestreamingUserService {

    @Autowired
    private SzUserMapper szUserMapper;

    @Autowired
    private SZRuleCache ruleCache;

    @Autowired
    private SzWithdrawalRecordMapper szWithdrawalRecordMapper;

    @Autowired
    private SzEnergyRecordMapper szEnergyRecordMapper;

    @Autowired
    private SzWithdrawalDetailMapper szWithdrawalDetailMapper;

    @Autowired
    private SzPlayTourRecordMapper szPlayTourRecordMapper;

    @Autowired
    private SzWalletDetailMapper szWalletDetailMapper;

    @Autowired
    private SzGiftMapperMP szGiftMapperMP;

    @Autowired
    private SzVipUpgradeRecordMapper szVipUpgradeRecordMapper;

    @Autowired
    private SzDeductionAmountRecordMapper szDeductionAmountRecordMapper;

    @Autowired
    private SzUserBankCardMapper szUserBankCardMapper;



    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult balanceWithdrawal(String userId, String paymentPassword, BigDecimal amount, String remark) {
        SzUser user = szUserMapper.selectById(userId);
        if (user == null){
            return AjaxResult.error("用户异常，请联系管理员");
        }

        if (StringUtil.isEmpty(user.getPhone())){
            return AjaxResult.error("用户异常，请联系管理员");
        }

        if (StringUtil.isEmpty(user.getPaymentPassword())){
            return AjaxResult.error("请先设置支付密码");
        }

        if (!user.getPaymentPassword().equals(paymentPassword)){
            return AjaxResult.error("支付密码错误");
        }

        if (szUserBankCardMapper.selectCount(new LambdaQueryWrapper<SzUserBankCard>().eq(SzUserBankCard::getUserId, userId).eq(SzUserBankCard::getDeleteFlag, "0")) == 0){
            return AjaxResult.error("请绑定银行卡后再进行提现！");
        }

        if (BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(user.getFrozenAccount()).get().compareTo(amount) < 0){
            return AjaxResult.error("提现钱包余额不足");
        }

        if (user.getSzEnergy().compareTo(amount) < 0){
            return AjaxResult.error("能量值不足");
        }

        if (user.getDeductionAmount().compareTo(BigDecimal.ZERO) != 0){
            return AjaxResult.error("非正常用户，完成还款后可正常提现");
        }

        SzUserBankCard bankCard = szUserBankCardMapper.selectOne(new LambdaQueryWrapper<SzUserBankCard>().eq(SzUserBankCard::getUserId, userId).eq(SzUserBankCard::getDeleteFlag, "0"));
        this.insertWithdrawalRecord(userId, bankCard.getCardId(), amount, remark);

        return AjaxResult.success("提现成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult rewardWithGifts(Long userId, Long rewardedUser, Long giftId, BigDecimal price, BigDecimal count) {
        SzUser user = szUserMapper.selectById(userId);
        // 计算礼物总价值
        BigDecimal totalValue = BigDecimalChain.chain(price).mul(count).get();
        if (user.getSzWalletBalance() == null || user.getSzWalletBalance().compareTo(BigDecimal.ZERO) == 0 ||
                BigDecimalChain.chain(user.getSzWalletBalance()).sub(user.getPendingActivationBalance()).get().compareTo(totalValue) < 0){
            return AjaxResult.error("可用余额不足");
        }

        log.info("用户{}给用户id:{} 打赏了礼物:{}，{}个，单价{}，总额{}，获得可提现余额{}",
                user.getNickname(), rewardedUser, count, price, totalValue, totalValue);
        SzPlayTourRecord playTourRecord = new SzPlayTourRecord();
        playTourRecord.setFromPerson(userId);
        playTourRecord.setToPerson(rewardedUser);
        playTourRecord.setMoney(totalValue);
        playTourRecord.setType(giftId);
        playTourRecord.setUnitPrice(price);
        playTourRecord.setCount(count.intValue());
        playTourRecord.setCreateTime(LocalDateTime.now());
        szPlayTourRecordMapper.insert(playTourRecord);
        log.info("打赏记录表插入成功");

        SzWalletDetail walletDetail = new SzWalletDetail();
        walletDetail.setUserId(userId);
        walletDetail.setMoney(totalValue);
        walletDetail.setFlowType("1"); // 打赏
        walletDetail.setPlayTour(playTourRecord.getId());
        walletDetail.setCreateTime(LocalDateTime.now());
        szWalletDetailMapper.insert(walletDetail);
        log.info("余额明细记录保存成功");

        SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        withdrawalDetail.setUserId(userId);
        withdrawalDetail.setMoney(totalValue);
        withdrawalDetail.setFlowType("4"); //打赏获得
        withdrawalDetail.setPlayTour(playTourRecord.getId());
        withdrawalDetail.setCreateTime(LocalDateTime.now());
        szWithdrawalDetailMapper.insert(withdrawalDetail);
        log.info("提现余额明细记录插入成功");

        user.setSzWalletBalance(BigDecimalChain.chain(user.getSzWalletBalance()).sub(totalValue).get());
        user.setSzWithdrawalBalance(BigDecimalChain.chain(user.getSzWithdrawalBalance()).add(totalValue).get());
        szUserMapper.updateById(user);
        log.info("用户余额扣减成功，提现余额增加成功");
        return AjaxResult.success();
    }

    @Override
    public AjaxResult getSzGift() {
        List<SzGiftMP> szGiftMPS = szGiftMapperMP.selectList(new LambdaQueryWrapper<SzGiftMP>().eq(SzGiftMP::getIsListing, "1"))
                .stream().peek(szGiftMP -> szGiftMP.setName(szGiftMP.getName() + "  (" + szGiftMP.getRealPrice().toString() + "元)")).collect(Collectors.toList());
        return AjaxResult.success(szGiftMPS);
    }

    @Override
    public AjaxResult getSzanchor() {
        List<SzUser> szUsers = szUserMapper.selectList(new LambdaQueryWrapper<SzUser>()
                .in(SzUser::getSzEnable, "1", "2")
                .select(SzUser::getId, SzUser::getNickname));
        return AjaxResult.success(szUsers);
    }

    @Override
    public AjaxResult vipUpgradeRecord(Long userId) {
        List<Map<String, String>> list = szUserMapper.vipUpgradeRecord(userId);
        return AjaxResult.success(list);
    }


    @Override
    @Transactional
    public AjaxResult updateUserVip(Long userId, Long vipId) {
        SzUser user = szUserMapper.selectById(userId);

        if (user.getSzEnable().equals("0")){
            return AjaxResult.error(user.getNickname() + "未开通数字人直播，无法修改代理等级");
        }

        if (vipId == user.getSzAgency()){
            return AjaxResult.success();
        }

        user.setSzAgency(vipId);
        szUserMapper.updateById(user);

        SzVipUpgradeRecord recentRecord = szVipUpgradeRecordMapper.selectList(new LambdaQueryWrapper<SzVipUpgradeRecord>()
                .eq(SzVipUpgradeRecord::getUserId, userId)
                .orderByDesc(SzVipUpgradeRecord::getCreateTime)).get(0);
        Long day = Duration.between(recentRecord.getCreateTime(), LocalDateTime.now()).toDays();
        recentRecord.setBeforeVip(recentRecord.getVipId());
        recentRecord.setVipId(vipId);
        recentRecord.setId(null);
        recentRecord.setCreateTime(LocalDateTime.now());
        recentRecord.setElapsedDay(day.intValue());
        recentRecord.setCreate_user(SecurityUtils.getUserId());
        szVipUpgradeRecordMapper.insert(recentRecord);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult deductionAmountRecord(Long userId) {
        List<Map<String, String>> list = szUserMapper.deductionAmountRecord(userId);
        return AjaxResult.success(list);
    }

    @Override
    @Transactional
    public AjaxResult updateDeduction(String userId, BigDecimal amount) {
        SzUser user = szUserMapper.selectById(userId);

        if (BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(user.getFrozenAccount()).get().compareTo(amount) < 0){
            return AjaxResult.error("还款金额不能大于可提现余额！");
        }

        if (user.getDeductionAmount().compareTo(amount) < 0){
            return AjaxResult.error("还款金额不能大于待还款金额！");
        }

        SzDeductionAmountRecord deductionAmountRecord = new SzDeductionAmountRecord();
        deductionAmountRecord.setUserId(user.getId());
        deductionAmountRecord.setAmount(amount);
        deductionAmountRecord.setType("3");
        deductionAmountRecord.setCreateTime(LocalDateTime.now());
        deductionAmountRecord.setBeforAmount(user.getDeductionAmount());

        // 扣除可提现余额  扣除带还款金额
        user.setSzWithdrawalBalance(BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(amount).get());
        user.setDeductionAmount(BigDecimalChain.chain(user.getDeductionAmount()).sub(amount).get());
        szUserMapper.updateById(user);

        // 插入待还款余额变化记录
        deductionAmountRecord.setAfterAmount(user.getDeductionAmount());
        szDeductionAmountRecordMapper.insert(deductionAmountRecord);

        // 插入可提现余额变化记录
        SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        withdrawalDetail.setUserId(user.getId());
        withdrawalDetail.setMoney(amount);
        withdrawalDetail.setFlowType("8");
        withdrawalDetail.setCreateTime(LocalDateTime.now());
        withdrawalDetail.setDeductionId(deductionAmountRecord.getId());
        szWithdrawalDetailMapper.insert(withdrawalDetail);

        // 判断是否可转为正常用户
        if (user.getDeductionAmount().compareTo(BigDecimal.ZERO) == 0){
            // 转为正常用户
            user.setSzEnable("1");
            szUserMapper.updateById(user);

            // 更新所有上级，由于他所获得的奖励
            updateParentAward(user.getId());
        }

        return AjaxResult.success();
    }

    private void updateParentAward(Long userId) {
        synchronized (this) {
            szUserMapper.updateUserPendingActivationBalance(userId);
            szUserMapper.updateUserWalletDetail(userId);
            szUserMapper.updateUserAwardRecord(userId);
        }
        log.info("更新所有上级，由于他所获得的奖励成功");
    }


    /**
     * 提现流程系统记录
     */
    private void insertWithdrawalRecord(String userId, String account, BigDecimal amount, String remark){
        SzUser user = szUserMapper.selectById(userId);
        SzOtherRule otherRule = ruleCache.getOtherRule();
        BigDecimal actualArrival = BigDecimalChain.chain(amount)
                .sub(BigDecimalChain.chain(amount).mul(otherRule.getExtractRatio()).get())
                .sub(BigDecimalChain.chain(amount).mul(otherRule.getRevenueRatio()).get()).get();
        log.info("用户{}发起提现操作，本次提现金额为{}，税收比例{}，提现手续费{}，提现账号{}，实际到账{}，备注{}",
                user.getNickname(), account, otherRule.getRevenueRatio(), otherRule.getExtractRatio(), account, actualArrival, remark);

        SzWithdrawalRecord withdrawalRecord = new SzWithdrawalRecord();
        withdrawalRecord.setUserId(Long.parseLong(userId));
        withdrawalRecord.setMoney(amount);
        withdrawalRecord.setApplicationTime(LocalDateTime.now());
        withdrawalRecord.setState("1"); //待处理
        //withdrawalRecord.setHandleTime(LocalDateTime.now());
        withdrawalRecord.setRemark(remark);
        //withdrawalRecord.setPayId(generateOrderId());
        withdrawalRecord.setExtractRatio(otherRule.getExtractRatio());
        withdrawalRecord.setRevenueRatio(otherRule.getRevenueRatio());
        withdrawalRecord.setExtractMoney(BigDecimalChain.chain(amount).mul(otherRule.getExtractRatio()).get());
        withdrawalRecord.setRevenueMoney(BigDecimalChain.chain(amount).mul(otherRule.getRevenueRatio()).get());
        withdrawalRecord.setEnergy(amount);
        withdrawalRecord.setAccount(account);
        withdrawalRecord.setActualArrival(actualArrival);
        withdrawalRecord.setWithdrawalMethod("2"); //支付方式 银行卡
        szWithdrawalRecordMapper.insert(withdrawalRecord);
        log.info("保存提现记录成功");

        //提现余额暂不更新
        user.setSzWithdrawalBalance(BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(amount).get());
        user.setSzEnergy(BigDecimalChain.chain(user.getSzEnergy()).sub(amount).get());
        szUserMapper.updateById(user);
        log.info("扣除提现余额、能量值成功");

//        SzEnergyRecord energyRecord = new SzEnergyRecord();
//        energyRecord.setUserId(Long.parseLong(userId));
//        energyRecord.setCreateTime(LocalDateTime.now());
//        energyRecord.setEnergy(amount);
//        energyRecord.setType("2");
//        szEnergyRecordMapper.insert(energyRecord);
        log.info("保存能量值变化明细成功");

        SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        withdrawalDetail.setUserId(Long.parseLong(userId));
        withdrawalDetail.setMoney(amount);
        withdrawalDetail.setFlowType("11"); // 提现暂扣
        withdrawalDetail.setTakeoutId(withdrawalRecord.getId());
        withdrawalDetail.setCreateTime(LocalDateTime.now());
        szWithdrawalDetailMapper.insert(withdrawalDetail);
        log.info("保存提现钱包明细记录成功");
    }


    private static String generateOrderId() {
        long timestamp = System.currentTimeMillis();
        String random = UUID.randomUUID().toString().replaceAll("-", "");
        log.info("生成交易订单号：{}", timestamp + random);
        return timestamp + random;
    }

    /**
     * 新数字直播-礼物打赏
     * @param vo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult innerRewardWithGifts(RewardWithVO vo) throws Exception {
        SzUser user = szUserMapper.selectById(vo.getUserId());
        // 计算礼物总价值
        BigDecimal totalValue = BigDecimalChain.chain(vo.getPrice()).mul(vo.getCount()).get();
        if (user.getSzWalletBalance() == null || user.getSzWalletBalance().compareTo(BigDecimal.ZERO) == 0 ||
                BigDecimalChain.chain(user.getSzWalletBalance()).sub(user.getPendingActivationBalance()).get().compareTo(totalValue) < 0){
            return AjaxResult.error("可用余额不足");
        }

        log.info("用户{}给用户id:{} 打赏了礼物:{}，{}个，单价{}，总额{}，获得可提现余额{}",
                user.getNickname(), vo.getRewardedUser(), vo.getCount(), vo.getPrice(), totalValue, totalValue);
        SzPlayTourRecord playTourRecord = new SzPlayTourRecord();
        playTourRecord.setFromPerson(vo.getUserId());
        playTourRecord.setToPerson(vo.getRewardedUser());
        playTourRecord.setMoney(totalValue);
        playTourRecord.setType(vo.getGiftId());
        playTourRecord.setUnitPrice( vo.getPrice());
        playTourRecord.setCount(vo.getCount().intValue());
        playTourRecord.setCreateTime(LocalDateTime.now());
        szPlayTourRecordMapper.insert(playTourRecord);
        log.info("打赏记录表插入成功");

        SzWalletDetail walletDetail = new SzWalletDetail();
        walletDetail.setUserId(vo.getUserId());
        walletDetail.setMoney(totalValue);
        walletDetail.setFlowType("1"); // 打赏
        walletDetail.setPlayTour(playTourRecord.getId());
        walletDetail.setCreateTime(LocalDateTime.now());
        szWalletDetailMapper.insert(walletDetail);
        log.info("余额明细记录保存成功");

        // SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        // withdrawalDetail.setUserId(vo.getUserId());
        // withdrawalDetail.setMoney(totalValue);
        // withdrawalDetail.setFlowType("4"); //打赏获得
        // withdrawalDetail.setPlayTour(playTourRecord.getId());
        // withdrawalDetail.setCreateTime(LocalDateTime.now());
        // szWithdrawalDetailMapper.insert(withdrawalDetail);
        // log.info("提现余额明细记录插入成功");

        user.setSzWalletBalance(BigDecimalChain.chain(user.getSzWalletBalance()).sub(totalValue).get());
        szUserMapper.updateById(user);
        log.info("用户余额扣减成功，提现余额增加成功");

        //调用新派直播应用修改钱包余额
        HashMap<String, Object> map = new HashMap<>(10);
        map.put("payType","reward");
        map.put("payMethod","reward");
        map.put("amount",totalValue);
        String resultStr = HttpClientUtil.httpPost("http://localhost:8001/v3/member/front/balanceRecharge/reward", map, vo.getToken());
        if (StringUtils.isBlank(resultStr)){
            throw new BaseException("调用打赏接口失败：v3/member/front/balanceRecharge/reward");
        }
        if(200!=JSONObject.parseObject(resultStr).getInteger("state")){
            throw new BaseException("调用打赏接口失败2：v3/member/front/balanceRecharge/reward");
        }
        return AjaxResult.success();
    }
}
